package com.example.filter;

import cn.hutool.json.JSONUtil;
import com.example.entity.MyHttpRequest;
import com.example.entity.MyHttpResponse;
import com.example.util.RsaUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

/** 用于解密请求加密响应的过滤器
 *
 * @email: pengyujun53@163.com
 * @author: peng_YuJun
 * @date: 2022/11/19
 * @time: 13:10
 */
@Slf4j
@WebFilter
public class DoCodecFilter implements Filter {
    /**
     * 忽略拦截的名单
     */
    private String[] excludedUris;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //初始，获取忽略拦截的名单
        String param = filterConfig.getInitParameter("excludedUris");
        if (StringUtils.hasText(param)) {
            this.excludedUris = param.split(",");
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("application/json");
        resp.setHeader("Access-Control-Allow-Origin", "*");
        resp.setHeader("Access-Control-Allow-Credentials", "true");
        resp.setHeader("Access-Control-Allow-Methods", "*");
        resp.setHeader("Access-Control-Allow-Headers", "Content-Type,Access-Token");
        resp.setHeader("Access-Control-Expose-Headers", "*");
        if (request.getMethod().equals(RequestMethod.OPTIONS.toString())){
            // 空请求
            return;
        }

        MyHttpRequest requestWrapper = new MyHttpRequest(request);
        requestWrapper.setCharacterEncoding("UTF-8");
        MyHttpResponse responseWrapper = new MyHttpResponse(resp);
        responseWrapper.setCharacterEncoding("UTF-8");
        responseWrapper.setContentType("application/json");

        //判断是否需要加解密的标识
        boolean isDocodec = false;

        // 定义表示变量 并验证用户请求URI 是否包含不过滤路径
        boolean flag = false;
        if (excludedUris!=null)
            for (String uri:excludedUris) {
                if (requestWrapper.getRequestURI().contains(uri)){
                    flag = true;
                    break;
                }
            }

        if(!flag){ //不在忽略拦截名单上，需要拦截
            if (requestWrapper.getMethod().equals(HttpMethod.GET.name())) {// get请求
                // 对参数进行处理，得到新的参数，将参数重新设置到request中
                String data = requestWrapper.getParameter("d");
                if (data!=null){
                    isDocodec = true;
                    Map<String, Object> params = decodeHandle(data);
                    requestWrapper.setParameters(params);
                }
            } else { // post请求，这里只对x-www-form-urlencoded类型进行处理 若是json类型的请求，则要另外做法
                String data = requestWrapper.getParameter("d");
                if (data!=null){
                    isDocodec = true;
                    Map<String, Object> params = decodeHandle(data);
                    requestWrapper.setParameters(params);
                }
            }

            //执行业务逻辑 交给下一个过滤器或servlet处理
            filterChain.doFilter(requestWrapper, responseWrapper);

            String content = responseWrapper.getContent();
            if (isDocodec){
                //加密返回响应
                content = encodeHandle(content);
            }
            PrintWriter writer = resp.getWriter();
            writer.print(content);
            writer.flush();
            writer.close();
        }else { //在忽略拦截名单上，不需要拦截
            filterChain.doFilter(servletRequest, servletResponse);
        }

    }

    /**
     * 解密操作
     * @param params
     * @return
     */
    public static Map<String, Object> decodeHandle(String params) {
        // 自定义参数的处理逻辑，最后将参数以map形式返回回去
        // ......
        //解密
        try {
            params = URLDecoder.decode(params,"utf-8");
            params = RsaUtil.decrpt(params,RsaUtil.getPrivateKey()); //RSA解密
            //params = DESHelper.decrypt(params); //DES解密
        } catch (Exception e) {
            log.error("解密出现问题!");
        }

        Map map = new HashMap();
        if (StringUtils.hasText(params)){
            try{
                map = JSONUtil.toBean(params, Map.class);
            }catch (Exception e){
                //若是使用Rsa加解密，偶尔会发生Rsa解密失败，从而导致转Map的错误抛出，大概率是Rsa解密不稳定，小概率事件
                log.error("解密出来的数据格式不符合json格式，导致转Map失败");
            }
        }

        return map;
    }

    /**
     * 加密操作
     * @param params
     * @return
     */
    public static String encodeHandle(String params){
        String encodeStr = null;
        try {
            encodeStr = RsaUtil.encrpt(params,RsaUtil.getPublicKey());  //RSA加密
//            encodeStr = DESHelper.encrypt(params); //DES加密
        } catch (Exception e) {
            log.error("加密出现问题! ");
        }
        return encodeStr;
    }

    @Override
    public void destroy() {

    }
}
